﻿using UnityEngine;
using System;

public class MJLogic
{
    /** 花色掩码 */
    private static byte MASK_COLOR = 0xF0;
    /** 数值掩码 */
    private static byte MASK_VALUE = 0x0F;
    //扑克数据
    public static byte[] CardDataArray =
    {
        0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,//条
		0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,//筒
		0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,//万
		0x31,0x41,0x51,0x61,//东，南，西，北
		0x71,0x81,0x91,//中发白
	};
    /** 获取数值 */
    public static byte getCardValue(byte cardData)
    {
        return (byte)(cardData & MASK_VALUE);
    }
    /** 获取花色 */
    public static byte getCardColor(byte cardData)
    {
        return (byte)((cardData & MASK_COLOR) / 16);
    }
    /** 检查胡牌 */
    public static byte[][] CheckHu(byte[] cardData, byte[] laizi = null)
    {
        return CheckHu(cardData, 1, (cardData.Length - 2) / 3, laizi);
    }
    /** 检查胡牌（应付特殊规则，比如对子为多个的时候或者7对） */
    public static byte[][] CheckHu(byte[] cardData, int twoNum, int threeNum, byte[] laizi)
    {
        return CheckHu(cardData, twoNum, threeNum, null, laizi);
    }
    private static byte[][] CheckHu(byte[] cardData, int twoNum, int threeNum, byte[][] saveMajing, byte[] laizi)
    {
        if (cardData == null)
        {
            if (twoNum == 0 && threeNum == 0)
            {
                return saveMajing;
            }
            else
            {
                return null;
            }
        }
        if (cardData.Length == ((twoNum * 2) + (threeNum * 3)))
        {
            if (threeNum > 0)
            {
                int[][] indexs = SiphonThreeIndexs(cardData.Length);
                for (var i = 0; i < indexs.Length; i++)
                {
                    var index = indexs[i];
                    var card0 = cardData[index[0]];
                    var card1 = cardData[index[1]];
                    var card2 = cardData[index[2]];
                    if (IsCanThree(card0, card1, card2, laizi))
                    {
                        byte[][] saveMajiangesCache = AppendSomeMajiang(saveMajing, new byte[] { cardData[index[0]], cardData[index[1]], cardData[index[2]] });
                        byte[][] majiangesReturn = CheckHu(RemoveSomeMajiang(cardData, new int[] { index[0], index[1], index[2] }), twoNum, threeNum - 1, saveMajiangesCache, laizi);
                        if (majiangesReturn != null)
                        {
                            return majiangesReturn;
                        }
                    }
                }
            }
            else if (twoNum > 0)
            {
                int[][] indexs = SiphonTwoIndexs(cardData.Length);
                if (indexs == null)
                {

                    return null;
                }
                for (var i = 0; i < indexs.Length; i++)
                {
                    var index = indexs[i];
                    var card0 = cardData[index[0]];
                    var card1 = cardData[index[1]];
                    if (IsCanTwo(card0, card1, laizi))
                    {
                        byte[][] saveMajiangesCache = AppendSomeMajiang(saveMajing, new byte[] { cardData[index[0]], cardData[index[1]] });
                        byte[][] mahjongTilesesReturn = CheckHu(RemoveSomeMajiang(cardData, new int[] { index[0], index[1] }), twoNum - 1, threeNum, saveMajiangesCache, laizi);
                        if (mahjongTilesesReturn != null)
                        {
                            return mahjongTilesesReturn;
                        }
                    }
                }
            }
            else
            {
                return saveMajing;
            }
        }
        return null;
    }
    private static byte[][] AppendSomeMajiang(byte[][] saveMajing, byte[] majiang)
    {
        if (saveMajing == null)
        {
            byte[][] majiangesReturn = new byte[1][];
            majiangesReturn[0] = majiang;
            return majiangesReturn;
        }
        else
        {
            byte[][] majiangesReturn = new byte[saveMajing.Length + 1][];
            Array.Copy(saveMajing, 0, majiangesReturn, 0, saveMajing.Length);
            majiangesReturn[saveMajing.Length] = majiang;
            return majiangesReturn;
        }
    }
    private static byte[] RemoveSomeMajiang(byte[] majiangs, int[] indexs)
    {
        int lenNew = majiangs.Length - indexs.Length;
        if (lenNew > 0)
        {
            byte[] majiangNew = new byte[lenNew];
            int index = 0;
            for (int i = 0; i < majiangs.Length; i++)
            {
                bool isAppend = true;
                for (int j = 0; j < indexs.Length; j++)
                {
                    if (i == indexs[j])
                    {
                        isAppend = false;
                        break;
                    }
                }
                if (isAppend)
                {
                    majiangNew[index] = majiangs[i];
                    index++;
                }
            }
            return majiangNew;
        }
        return null;
    }
    private static bool IsCanThree(byte card0, byte card1, byte card2, byte[] laizi)
    {
        if (card0 == card1 && card1 == card2)
        {
            return true;
        }
        if (Mathf.Abs(card0 - card1) == 1 && Mathf.Abs(card1 - card2) == 1)
        {
            return true;
        }
        //以下是赖子判断
        if (laizi == null)
        {
            laizi = new byte[] { };
        }
        bool card0IsLaizi = false;
        bool card1IsLaizi = false;
        bool card2IsLaizi = false;
        var laiziCount = 0;
        if (Array.IndexOf(laizi, card0) != -1)
        {
            laiziCount++;
            card0IsLaizi = true;
        }
        if (Array.IndexOf(laizi, card1) != -1)
        {
            laiziCount++;
            card1IsLaizi = true;
        }
        if (Array.IndexOf(laizi, card2) != -1)
        {
            laiziCount++;
            card2IsLaizi = true;
        }
        if (laiziCount >= 2)//如果超过2个赖子
        {
            return true;
        }
        else if (laiziCount == 1)
        {
            if (card0IsLaizi)
            {
                if (Mathf.Abs(card1 - card2) <= 2)
                {
                    return true;
                }
            }
            if (card1IsLaizi)
            {
                if (Mathf.Abs(card0 - card2) <= 2)
                {
                    return true;
                }
            }
            if (card2IsLaizi)
            {
                if (Mathf.Abs(card0 - card1) <= 2)
                {
                    return true;
                }
            }
        }
        return false;
    }
    private static bool IsCanTwo(byte card0, byte card1, byte[] laizi)
    {
        if (card0 == card1)
        {
            return true;
        }
        //以下是赖子判断
        if (laizi == null)
        {
            laizi = new byte[] { };
        }
        if (Array.IndexOf(laizi, card0) != -1 || Array.IndexOf(laizi, card1) != -1)
        {
            return true;
        }
        return false;
    }
    //从数组长度为arrayLen的整形数组中任意抽取两个元素，把所有可能的组合的索引列成一个二位数组返回出来
    private static int[][] SiphonThreeIndexs(int arrayLen)
    {
        int len = (arrayLen * (arrayLen - 1) * (arrayLen - 2)) / 6;
        if (len > 0)
        {
            int[][] indexs = new int[len][];
            int index = 0;
            for (int i = 0; i < arrayLen; i++)
            {
                for (int j = (i + 1); j < arrayLen; j++)
                {
                    for (int k = (j + 1); k < arrayLen; k++)
                    {
                        indexs[index] = new int[3];
                        indexs[index][0] = i;
                        indexs[index][1] = j;
                        indexs[index][2] = k;
                        index++;
                    }
                }
            }
            return indexs;
        }
        else
        {
            return null;
        }
    }
    //从数组长度为arrayLen的整形数组中任意抽取两个元素，把所有可能的组合的索引列成一个二位数组返回出来
    private static int[][] SiphonTwoIndexs(int arrayLen)
    {
        int len = (arrayLen * (arrayLen - 1)) / 2;
        if (len > 0)
        {
            int[][] indexs = new int[len][];
            int index = 0;
            for (int i = 0; i < arrayLen; i++)
            {
                for (int j = (i + 1); j < arrayLen; j++)
                {
                    indexs[index] = new int[2];
                    indexs[index][0] = i;
                    indexs[index][1] = j;
                    index++;
                }
            }
            return indexs;
        }
        else
        {
            return null;
        }
    }
}
